package net.guerlab.smart.qcloud.im.callbackcommand;

import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.extern.slf4j.Slf4j;
import net.guerlab.smart.qcloud.im.ImConstants;
import net.guerlab.smart.qcloud.im.ImException;
import net.guerlab.smart.qcloud.im.callbackcommand.c2c.ClientToClientAfterSendMsgCallbackCommand;
import net.guerlab.smart.qcloud.im.callbackcommand.c2c.ClientToClientBeforeSendMsgCallbackCommand;
import net.guerlab.smart.qcloud.im.callbackcommand.group.*;
import net.guerlab.smart.qcloud.im.callbackcommand.sns.BlackListAddCallbackCommand;
import net.guerlab.smart.qcloud.im.callbackcommand.sns.BlackListDeleteCallbackCommand;
import net.guerlab.smart.qcloud.im.callbackcommand.sns.FriendAddCallbackCommand;
import net.guerlab.smart.qcloud.im.callbackcommand.sns.FriendDeleteCallbackCommand;
import net.guerlab.smart.qcloud.im.callbackcommand.state.StateChangeCallbackCommand;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;

/**
 * 回调命令工具
 *
 * @author guer
 */
@Slf4j
public class CallbackCommandUtils {

    private static final Map<String, Class<? extends AbstractCallbackCommand>> CALLBACK_COMMAND_CLASS_MAP = new HashMap<>();

    static {
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_STATE_STATECHANGE, StateChangeCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP.put(ImConstants.CALLBACK_COMMAND_SNS_FRIEND_ADD, FriendAddCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_SNS_FRIEND_DELETE, FriendDeleteCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_SNS_BLACK_LIST_ADD, BlackListAddCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_SNS_BLACK_LIST_DELETE, BlackListDeleteCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP.put(ImConstants.CALLBACK_COMMAND_C2C_BEFORE_SEND_MSG,
                ClientToClientBeforeSendMsgCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_C2C_AFTER_SEND_MSG, ClientToClientAfterSendMsgCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_GROUP_BEFORE_CREATE_GROUP, BeforeCreateGroupCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_GROUP_AFTER_CREATE_GROUP, AfterCreateGroupCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP.put(ImConstants.CALLBACK_COMMAND_GROUP_BEFORE_APPLY_JOIN_GROUP,
                BeforeApplyJoinGroupCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP.put(ImConstants.CALLBACK_COMMAND_GROUP_BEFORE_INVITE_JOIN_GROUP,
                BeforeInviteJoinGroupCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_GROUP_AFTER_NEW_MEMBER_JOIN, AfterNewMemberJoinCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_GROUP_AFTER_MEMBER_EXIT, AfterMemberExitCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_GROUP_BEFORE_SEND_MSG, GroupBeforeSendMsgCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_GROUP_AFTER_SEND_MSG, GroupAfterSendMsgCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP
                .put(ImConstants.CALLBACK_COMMAND_GROUP_AFTER_GROUP_FULL, AfterGroupFullCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP.put(ImConstants.CALLBACK_COMMAND_GROUP_AFTER_GROUP_DESTROYED,
                AfterGroupDestroyedCallbackCommand.class);
        CALLBACK_COMMAND_CLASS_MAP.put(ImConstants.CALLBACK_COMMAND_GROUP_AFTER_GROUP_INFO_CHANGED,
                AfterGroupInfoChangedCallbackCommand.class);
    }

    private CallbackCommandUtils() {

    }

    /**
     * 解析回调命令
     *
     * @param callbackCommand
     *         回调命令字
     * @param data
     *         数据
     * @param objectMapper
     *         objectMapper
     * @return 回调命令
     */
    public static AbstractCallbackCommand parse(String callbackCommand, String data, ObjectMapper objectMapper) {
        Class<? extends AbstractCallbackCommand> clazz = CALLBACK_COMMAND_CLASS_MAP.get(callbackCommand);

        log.debug("callbackCommand: {}, class: {}, original data: {}", callbackCommand, clazz, data);

        if (clazz == null) {
            return null;
        }

        try {
            AbstractCallbackCommand entity = objectMapper.readValue(data, clazz);
            log.debug("parsed data: {}", entity);
            return entity;
        } catch (IOException e) {
            throw new ImException(e.getLocalizedMessage(), e);
        }
    }

}
